let arr = [
  [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}],
  [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}],
  [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}],
  [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}],
  [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}],
  [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}],
  [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}],
  [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}],
  [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}],
  [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}],
  [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}],
  [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}],
  [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}],
  [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}],
  [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}],
  [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}],
]
//渲染游戏区域
const renderTable = () => {
  document.querySelector('table').innerHTML = ''
  arr.forEach((item, index) => {
    //第一层遍历创建tr
    let tr = document.createElement('tr')
    tr.dataset.y = index
    item.forEach((item2, index2) => {
      //第二层遍历创建td
      let td = document.createElement('td')
      td.dataset.x = index2
      tr.appendChild(td)
    })
    document.querySelector('table').appendChild(tr)
  })
}
renderTable()
//渲染样式的函数
const renderColor = () => {
  arr.forEach((item, index) => {
    const trArr = document.querySelectorAll('tr')
    item.forEach((item2, index2) => {
      //头部渲染
      if (item2.head === 1) {
        trArr[index].querySelectorAll('td')[index2].classList.add('bgc3')
      }
      //身体渲染成黑色
      else if (item2.body === 1) {
        trArr[index].querySelectorAll('td')[index2].classList.remove('bgc3')
        trArr[index].querySelectorAll('td')[index2].classList.remove('bgc2')
        trArr[index].querySelectorAll('td')[index2].classList.add('bgc1')
      }
      //苹果渲染
      else if (item2.apple === 1) {
        trArr[index].querySelectorAll('td')[index2].classList.add('bgc2')
      }
      //如果是其他的值，就把这个样式清空
      else {
        trArr[index].querySelectorAll('td')[index2].className = ''
      }
    })
  })
}
//蛇头构造函数
function Head(x, y) {
  this.x = x
  this.y = y
  this.render = function (a) {
    arr[this.y][this.x].head = a
  }
}
//身体构造函数
function Body(x, y) {
  this.x = x
  this.y = y
  this.render = function (a) {
    arr[this.y][this.x].body = a
  }
}
//苹果构造函数
function Apple(x, y) {
  this.x = x
  this.y = y
  this.render = function (a) {
    arr[this.y][this.x].apple = a
  }
}
//依次渲染默认出现的头部，身体和苹果
let a = new Head(10, 10)
a.render(1)
//声明一个存放身体元素的数组,移动以及判断获胜都需要用到这个数组的功能
let bodyArr = []
let b = new Body(10, 11)
bodyArr.push(b)
b.render(1)
let c = new Apple(5, 5)
c.render(1)
renderColor()
//键盘控制事件
//控制移动方向的变量
let num = 1
document.addEventListener('keydown', function (e) {
  //flag是暂停功能的变量
  if (flag) {
    if (e.key === 'ArrowDown') {
      //蛇头只能够向左或者向右移动，否则冲太快容易死。也不可以调头。
      if (num == 2 || num == 4) {
        down()
        num = 3
      }
    } else if (e.key === 'ArrowRight') {
      if (num == 1 || num == 3) {
        right()
        num = 2
      }
    } else if (e.key === 'ArrowLeft') {
      if (num == 1 || num == 3) {
        left()
        num = 4
      }
    } else if (e.key === 'ArrowUp') {
      if (num == 2 || num == 4) {
        up()
        num = 1
      }
    }
  }
})
//上下左右移动函数
const up = () => {
  //用try catch来判断是否出界
  try { //把移动的函数写在try里面，如果出界了就会报错，然后走catch里的代码
    //移动的时候先清除当前格子的样式
    a.render(0)
    a.y -= 1
    //然后渲染新样式
    a.render(1)
  } catch {
    clearInterval(timer)
    alert('游戏结束!')
    location.reload()
  }
  //调用吃苹果函数
  eat()
  //让数组中的最后一个元素，移动到头部刚才所在的位置
  bodyArr[bodyArr.length - 1].render(0)
  //这个a.x,a.y+1就是头部移动前的坐标
  bodyArr[bodyArr.length - 1].x = a.x
  bodyArr[bodyArr.length - 1].y = a.y + 1
  bodyArr[bodyArr.length - 1].render(1)
  //把身体数组里的最后一个元素移到最开头
  bodyArr.unshift(bodyArr.pop())
  renderColor()
  //调用判断游戏结束函数
  end()
}
const down = () => {
  try {
    a.render(0)
    a.y += 1
    a.render(1)
  }
  catch {
    clearInterval(timer)
    alert('游戏结束!')
    location.reload()
  }
  eat()
  //让数组中的最后一个元素，移动到头部刚才所在的位置
  bodyArr[bodyArr.length - 1].render(0)
  bodyArr[bodyArr.length - 1].x = a.x
  bodyArr[bodyArr.length - 1].y = a.y - 1
  bodyArr[bodyArr.length - 1].render(1)
  bodyArr.unshift(bodyArr.pop())
  renderColor()
  end()
}
const right = () => {
  try {
    a.render(0)
    a.x += 1
    a.render(1)
  }
  catch {
    clearInterval(timer)
    alert('游戏结束!')
    location.reload()
  }
  eat()
  //让数组中的最后一个元素，移动到头部刚才所在的位置
  bodyArr[bodyArr.length - 1].render(0)
  bodyArr[bodyArr.length - 1].x = a.x - 1
  bodyArr[bodyArr.length - 1].y = a.y
  bodyArr[bodyArr.length - 1].render(1)
  bodyArr.unshift(bodyArr.pop())
  renderColor()
  end()
}
const left = () => {
  try {
    a.render(0)
    a.x -= 1
    a.render(1)
  }
  catch {
    clearInterval(timer)
    alert('游戏结束!')
    location.reload()
  }
  eat()
  //让数组中的最后一个元素，移动到头部刚才所在的位置
  bodyArr[bodyArr.length - 1].render(0)
  bodyArr[bodyArr.length - 1].x = a.x + 1
  bodyArr[bodyArr.length - 1].y = a.y
  bodyArr[bodyArr.length - 1].render(1)
  bodyArr.unshift(bodyArr.pop())
  renderColor()
  end()
}
//得分
let fen = 0
//吃苹果
const eat = () => {
  //如果头部和苹果重合了
  if (arr[a.y][a.x].apple == 1) {
    //清除这个苹果
    arr[a.y][a.x].apple = 0
    //分数加1
    fen++
    //调用判断游戏胜利函数
    win()
    //渲染分数
    document.querySelector('.defen span').innerHTML = fen
    //用循环来生成新苹果，满足条件就退出循环
    while (true) {
      const x = Math.floor(Math.random() * 16)
      const y = Math.floor(Math.random() * 16)
      //判断苹果不能出现在身体上
      if (!arr[y][x].head && !arr[y][x].body) {
        arr[y][x].apple = 1
        break
      }
    }
    //生成新的身体实例
    let b = new Body(bodyArr[bodyArr.length - 1].x, bodyArr[bodyArr.length - 1].y)
    b.render(1)
    bodyArr.push(b)
  }
}
//碰到身体游戏失败判定
const end = () => {
  //如果头部和身体重合了
  if (arr[a.y][a.x].body == 1) {
    clearInterval(timer)
    alert('游戏结束!')
    location.reload(true)
  }
}
//自动向前移动功能
let timer
//封装一个向前移动的函数
function move() {
  if (num == 1) {
    up()
  } else if (num == 2) {
    right()
  } else if (num == 3) {
    down()
  } else {
    left()
  }
}
//写自动移动的间歇函数
time()
function time() {
  //来个分越高速度越快的功能
  if (fen <= 20) {
    timer = setInterval(function () {
      move()
    }, 250)
  } else if (fen > 20 && fen <= 40) {
    clearInterval(timer)
    timer = setInterval(function () {
      move()
    }, 200)
  } else {
    clearInterval(timer)
    timer = setInterval(function () {
      move()
    }, 150)
  }
}
//暂停功能
let flag = true
document.addEventListener('keydown', function (e) {
  if (flag) {
    if (e.key === 'Enter') {
      clearInterval(timer)
      flag = !flag
    }
  } else {
    if (e.key === 'Enter') {
      time()
      flag = true
    }
  }
})
//胜利条件，身体数组的元素等于255个就获胜
const win = () => {
  if (bodyArr.length == 255) {
    clearInterval(timer)
    alert('游戏胜利!')
    location.reload()
  }
}